/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine - graphics/scene/collection
// Copyright (c) 2015.  All Rights Reserved
//
// File:		AEStaticGeometryInstanceCollection.h
// Author:		Gianluca Belardelli
// Date:		23/06/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESTATICGEOMETRYINSTANCECOLLECTION_H_
#define _AESTATICGEOMETRYINSTANCECOLLECTION_H_

/// \brief
///   Static geometry instance collection class
/// 
/// Subclass of the AERenderCollection class providing functionality for handling collections
/// of static geometry instances.
class AEStaticGeometryInstanceCollection : public AERenderCollection
{
public:
	/// \brief Costruttore della classe AEStaticGeometryInstanceCollection.
	/// L'array di puntatori AEStaticGeometryInstance verr&agrave; copiato nella Collection.
	/// \param uiNumEntries Numero di elementi da copiare.
	/// \param lpEntryList Puntatore all'array di puntatori da copiare.
	/// \param nSize Dimensione della Collection ( deve essere almeno nSize>=uiNumEntries
	///   Size of the collection (where iSize>=iNumEntries)
	/// 
	/// \param iMemGranularity
	///   Whenever additional elements are added to a collection, and the number of elements becomes
	///   too big for the currently allocated size of the collection, the collection is re-allocated.
	///   This parameter defines the increments of each re-allocation step.
	AE_DLLIMPEXP AEStaticGeometryInstanceCollection( AEUINT32 uiNumEntries, const AEStaticGeometryInstance **lpEntryList, AEUINT32 uiSize, AEUINT32 uiMemGranularity = 1024 );
	
	/// \brief
	///   Constructor of the AEStaticGeometryInstanceCollection class.
	/// 
	/// \param iSize
	///   Initial size of the static geometry instance collection in numbers of elements.
	/// 
	/// \param iMemGranularity
	///   Whenever additional elements are added to a collection, and the number of elements becomes
	///   too big for the currently allocated size of the collection, the collection is re-allocated.
	///   This parameter defines the increments of each re-allocation step.
	AE_DLLIMPEXP AEStaticGeometryInstanceCollection( AEUINT32 uiSize = 0, AEUINT32 uiMemGranularity = 1024 );
	
	/// \brief
	///   Destructor of the AEStaticGeometryInstanceCollection class
	/// 
	/// Cleans up the collection and deallocates all the memory associated with it.
	AE_DLLIMPEXP ~AEStaticGeometryInstanceCollection( void );
	
	/// \brief
	///   Determines the static geometry instances in the collection touching a given bounding box
	/// 
	/// The static geometry instances touching the bounding box are stored in the target collection.
	/// 
	/// \param box
	///   The bounding box against which the static geometry instances are compared
	/// 
	/// \param targetCollection
	///   The collection in which the static geometry instances touching the box are stored
	AE_DLLIMPEXP void DetermineEntriesTouchingBox( const AEBoundingBox &bbBox, AEStaticGeometryInstanceCollection &refTargetCollection ) const;
	
	/// \brief
	///   Determines the static geometry instances touching the negative/positive halfspace of the
	///   given plane
	/// 
	/// The static geometry instances touching the desired halfspace are stored in the target
	/// collection.
	/// 
	/// \param plane
	///   The plane against which the static geometry instances are compared
	/// 
	/// \param targetCollection
	///   The collection in which the static geometry instances touching the desired halfspace are
	///   stored
	/// 
	/// \param bNegativeHalfspace
	///   If TRUE, the static geometry instances touching the negative halfspace are added to the
	///   target collection; otherwise, the static geometry instances touching the positive halfspace
	///   are added.
	//AE_DLLIMPEXP void DetermineEntriesInHalfspace( const hkvPlane& plane, AEStaticGeometryInstanceCollection &refTargetCollection, AEBOOL32 bNegativeHalfspace) const;
	
	/// \brief
	///   Determines the static geometry instances in the collection touching a given frustum
	/// 
	/// The static geometry instances touching the frustum are stored in the target collection.
	/// 
	/// \param frustum
	///   The frustum against which the static geometry instances are compared
	/// 
	/// \param targetCollection
	///   The collection in which the static geometry instances touching the frustum are stored
	//AE_DLLIMPEXP void DetermineEntriesTouchingFrustum( const VisFrustum_cl &frustum, AEStaticGeometryInstanceCollection &refTargetCollection ) const;
	
	/// \brief
	///   Determines the static geometry instances in the collection touching a given convex volume
	/// 
	/// The static geometry instances touching the convex volume are stored in the target collection.
	/// 
	/// \param convexVolume
	///   The convex volume against which the static geometry instances are compared
	/// 
	/// \param targetCollection
	///   The collection in which the static geometry instances touching the convex volume are stored
	//AE_DLLIMPEXP void DetermineEntriesTouchingConvexVolume(const VisConvexVolume_cl &convexVolume, AEStaticGeometryInstanceCollection &targetCollection) const;
	
	/// \brief
	///   Non-virtual override
	AE_FORCEINLINE AEBOOL32 Contains( AEStaticGeometryInstance *lpMeshInstance ) const;
	
	/// \brief
	///   Filters out all static geometry instances in this collection that did not pass the last
	///   visibility check in the passed context.
	AE_DLLIMPEXP void FilterInvisibleEntries( AERenderContext *lpContext = AENULL );
	
	/// \brief
	///   Tags this collection of static geometry instances
	/// 
	/// \sa AEStaticGeometryInstance::Tag
	/// \sa AEStaticGeometryInstance::IsTagged
	/// \sa AEStaticGeometryInstance::ResetTags
	AE_DLLIMPEXP void TagEntries( void ) const;
	
	/// \brief
	///   Removes all entries from the collection that are tagged (via AEStaticGeometryInstance::Tag) or not tagged (bStatus=false)
	/// 
	/// \param bStatus
	///   The tag status to test. All elements with AEStaticGeometryInstance::IsTagged==bStatus are removed
	///
	/// \sa AEStaticGeometryInstance::Tag
	/// \sa AEStaticGeometryInstance::IsTagged
	/// \sa AEStaticGeometryInstance::ResetTags
	AE_DLLIMPEXP void RemoveWithTagStatus( AEBOOL32 bStatus );
	
	/// \brief
	///   Extracts the tagged static geometry instances from this collection into another collection.
	/// 
	/// The passed destination collection will be filled with the tagged static geometry instances,
	/// but it will not be cleared beforehand.
	/// 
	/// \param refDestCollection
	///   The destination collection that gets the tagged static geometry instances appended.
	/// \param bRequestedTagStatus
	///   true, to get all tagged instances, false to get all untagged
	///
	/// \sa AEStaticGeometryInstance::Tag
	/// \sa AEStaticGeometryInstance::IsTagged
	/// \sa AEStaticGeometryInstance::ResetTags
	AE_DLLIMPEXP void GetTaggedEntries( AEStaticGeometryInstanceCollection &refDestCollection, AEBOOL32 bRequestedTagStatus = AETRUE ) const;
	
	/// \brief
	///   Same as GetTaggedEntries but additionally filters by geometry type
	///   (VisStaticGeometryType_e)
	AE_DLLIMPEXP void GetTaggedEntriesOfType( AEStaticGeometryInstanceCollection &refDestCollection, AEStaticGeometryType eGeomType, AEBOOL32 bRequestedTagStatus = AETRUE ) const;
	
	/// \brief
	///   Returns all entries in the collection, filtered by geometry type
	AE_DLLIMPEXP void GetEntriesOfType( AEStaticGeometryInstanceCollection &refDestCollection, AEStaticGeometryType eGeomType ) const;
	
	/// \brief
	///   Computes the combined bounding box of all static geometry instances in this collection.
	/// 
	/// This operation can be quite expensive for large collections, so it is not recommended to call
	/// it too frequently.
	/// 
	/// \param Box
	///   The bounding box of the static geometry instances in this collection.
	AE_DLLIMPEXP void ComputeBoundingBox( AEBoundingBox &bbBox ) const;
	
	/// \brief
	///   Sorts the static geometry instance collection according to the specified criterion.
	/// 
	/// Valid criteria are: VIS_SORTING_DISTANCE: Sorts the elements front to back
	/// VIS_SORTING_PROXIMITY: Sorts the elements front to back VIS_SORTING_RENDERSTATE: Sorts the
	/// elements by render state VIS_SORTING_VERTEXBUFFER: Sorts the elements by vertex buffer
	/// 
	/// These values are mutually exclusive.
	/// 
	/// \param iFlags
	///   Sorting criterion as specified in the function description.
	/// 
	/// \param pContext
	///   Render context to use for the distance/proximity criteria. If set to NULL and the
	///   distance/proximity criteria are specified, the currently active render context is used.
	AE_DLLIMPEXP void Sort( AEINT32 nFlags, AERenderContext *lpContext = NULL );
	
	/// \brief
	///   Splits the collection according to the elements' lighting modes.
	/// 
	/// Lightmapped static geometry instances will end up in the "lightMapInstances" collection;
	/// non-lightmapped ones in the "lightGridInstances" collection. To original collection remains
	/// unmodified.
	/// 
	/// \param lightMapInstances
	///   Target collection for lightmapped static geometry instances.
	/// 
	/// \param lightGridInstances
	///   Target collection for non-lightmapped static geometry instances.
	AE_DLLIMPEXP void SplitLightingModes( AEStaticGeometryInstanceCollection &refLightMapInstances, AEStaticGeometryInstanceCollection &refLightGridInstances ) const;
	
	
	///
	/// @name Non-virtual Overridden Functions
	/// @{
	///
	
	/// \brief
	///   Casts the entry with given index to a AEStaticGeometryInstance pointer.
	AE_FORCEINLINE AEStaticGeometryInstance *GetEntry( AEUINT32 uiIndex ) const;
	
	/// \brief
	///   Appends a AEStaticGeometryInstance to this collection
	AE_FORCEINLINE void AppendEntry( AEStaticGeometryInstance *lpMeshInstance );
	
	/// \brief
	///   Appends a AEStaticGeometryInstance to this collection without range checking
	AE_FORCEINLINE void AppendEntryFast( AEStaticGeometryInstance *lpMeshInstance );
	
	/// \brief
	///   Returns the pointer to the AEStaticGeometryInstance collection list.
	AE_FORCEINLINE AEStaticGeometryInstance **GetDataPtr( void ) const;
	
	/// @}
};

#include "AEStaticGeometryInstanceCollection.inl"

#endif // _AESTATICGEOMETRYINSTANCECOLLECTION_H_

